feat: extension file reload — watch for plugin changes and hot-reload runtime#6347
Conversation
… runtime - Extract refreshExtensionRuntime to centralize MCP, skills, subagents, hooks, and memory refresh - Add ExtensionFileWatcher (chokidar) for auto-detecting extension file changes - Add ExtensionRefreshState with per-session scoped instance and mutation suppression - Replace monkey-patching with ExtensionManager native mutation listeners - Add /reload-plugins slash command with i18n-aware summary across all 9 locales - Add auto-refresh of extension content (commands/skills/agents) on file change - Add HookRegistry.reloadConfiguredHooks() with correct error recovery - Fix async mutation pairing via id-based Map instead of LIFO stack - Fix bootstrap watcher close() UB with queueMicrotask deferral - Fix concurrent refresh with runningRef/pendingRef guard - Fix error propagation from refreshExtensionContentRuntime to UI - Fix isIgnored cross-platform path splitting (path.sep → regex) - Fix wrong ExtensionMutationEvent type via import from core - Fix addItem on unmounted component with mountedRef guard - Set followSymlinks: false on chokidar watchers
qwen-code-ci-bot
left a comment
There was a problem hiding this comment.
This PR touches core infrastructure (packages/core/src/extension/*, packages/core/src/hooks/*) at scale — 781 changed lines in core paths (437 source + 344 tests), exceeding the 500-line threshold for non-maintainer PRs.
Core refactors of this scope must be maintainer-initiated. The changes introduce a mutation listener pattern across ~15 ExtensionManager methods, a new extension-runtime-refresh module, and hook registry reload capabilities — these are architectural decisions that need maintainer design review first.
@ZijianZhang989 — the direction looks interesting, but the scope of core changes requires a maintainer to sign off on the design. Could you open an issue to discuss the approach before proceeding? Specifically:
- The mutation listener pattern wrapping every
ExtensionManagerpublic method - The
refreshExtensionRuntimeextraction and its contract with callers - The
reloadConfiguredHooksrollback semantics inHookRegistry
Once there's alignment on the design, a maintainer can champion the implementation.
中文说明
此 PR 涉及核心基础设施(packages/core/src/extension/*、packages/core/src/hooks/*)的大规模变更——核心路径共 781 行变更(437 行源码 + 344 行测试),超出非维护者 PR 的 500 行阈值。
此规模的核心重构必须由维护者发起。变更包括在约 15 个 ExtensionManager 方法中引入变更监听器模式、新增 extension-runtime-refresh 模块、以及钩子注册表的重载能力——这些都是需要维护者先进行设计评审的架构决策。
@ZijianZhang989 —— 方向看起来很有意思,但核心变更的规模需要维护者先确认设计方案。能否先开一个 issue 讨论方案?具体包括:
- 包裹每个
ExtensionManager公开方法的变更监听器模式 refreshExtensionRuntime提取及其与调用方的契约HookRegistry中reloadConfiguredHooks的回滚语义
设计方案达成一致后,维护者可以推进实现。
— Qwen Code · qwen3.7-max
wenshao
left a comment
There was a problem hiding this comment.
Reviewed — no blockers. Suggestion-level recommendations are in the Suggestion summary comment below.
|
No new Suggestion-level findings this round — all prior suggestions have been addressed or superseded. — qwen3.7-max via Qwen Code /review |
qwen-code-ci-bot
left a comment
There was a problem hiding this comment.
Found 3 Critical issues around silent failure modes. The watcher architecture and mutation-wrapping design look solid overall, but three error paths silently swallow failures that previously propagated or that the user needs to know about. See inline comments.
✅ Hands-on verification (real binary) — merge referenceI built the real Verdict: yes. All three user-facing paths work in the live TUI, the author's 341 tests pass, and the suite provably bears weight under mutation. No functional regression observed. 1) Real TUI — the actual
|
| # | Trigger (on disk, live session) | Observed in the real TUI |
|---|---|---|
| A | add commands/farewell.md |
/farewell becomes resolvable inline, with no /reload-plugins (silent auto content-refresh) |
| B | edit qwen-extension.json (config) |
● Extensions changed on disk. Run /reload-plugins to apply updates. (one-shot prompt) |
| C | run /reload-plugins |
● Reloaded extensions: 1 extension · 2 commands · 1 skill · 1 agent · 0 hooks · 0 extension MCP servers · 0 extension LSP servers — the file hot-added in step A is counted |
2) Tests — author's suites + a real-fs E2E + adversarial mutation
- 341 / 341 of the PR's own tests pass (core 195 + cli 146, 11 files).
- Real chokidar E2E (added for this review): the shipped suite mocks
chokidar+node:fsand fires synthetic events, so I wrote a harness that drives the real watcher against a real temp dir with real edits. 9/9, deterministic across 4 runs —commands|skills|agents → content,hooks|qwen-extension.json|QWEN.md → stale, linked-extension source →content,.DS_Store|.swp|README.md → ignored. - Mutation testing — 5/5 caught: dropping
skillsfromAUTO_REFRESH_DIRS(RED in both unit and the real E2E),isSuppressed()→false, summary separator,throw hookReloadError, and dropping agent-scoped-hook preservation each turn the right suite RED and revert cleanly to green. --bare→ no watcher is gated in source (gemini.tsx:621,isBareMode(argv.bare) ? undefined : new ExtensionFileWatcher(...)) and covered by the bare-mode test.
Notes (non-blocking, for the record)
- The one error path that is surfaced rather than swallowed — hook-reload failure (
refreshExtensionRuntimere-throwshookReloadError) — is real and tested (mutation RED when thethrowis removed). The remaining silent paths (ENOSPC, MCP startup,/hooksdisable state across reload) are the author's explicitly-acknowledged out-of-scope items. - On macOS, FSEvents occasionally emits an incidental sibling re-stat under rapid multi-file writes. It is an OS-level watcher trait (reproduced with bare
chokidar, not specific to this PR) and is absorbed byawaitWriteFinish(200 ms) + the "prompt once" idempotency inExtensionRefreshState. Worst case is one extra/reload-pluginsprompt, never a wrong classification. - By design,
SUPPRESS_AFTER_MS = 1000means a user file edit made within ~1 s after a programmatic enable/disable settles is intentionally ignored (anti-self-trigger). Sensible tradeoff; just noting it.
Bottom line: behavior matches the description, error surfacing on the hook path works, and the tests hold. LGTM to merge from a verification standpoint. 🚢
🇨🇳 中文完整版
✅ 真实二进制动手验证 —— 合并参考
我用本 PR head(60750480,base 47f62a46)构建了真实的 qwen bundle,端到端跑通了该特性。core 从 PR 自身源码解析(用一条 esbuild alias 覆盖工作区符号链接),并确认 PR 代码确实进了 bundle(addMutationListener、Extensions changed on disk、reload-plugins 均在 dist/chunks/ 中命中)。这是对已有"no blockers" review 的补充——回答它是否真的按描述工作。
结论:是。 三条用户可见路径在真实 TUI 中全部工作,作者的 341 个测试全绿,且变异测试证明测试套件真正承重。未发现功能回归。
1)真实 TUI —— 真 qwen 二进制、隔离 HOME、demo 扩展、在磁盘上真实编辑
(见上方第一张图)
| # | 触发(磁盘上,会话进行中) | 真实 TUI 中的观察 |
|---|---|---|
| A | 新增 commands/farewell.md |
/farewell 无需 /reload-plugins 即内联可用(静默自动内容刷新) |
| B | 编辑 qwen-extension.json(配置) |
● Extensions changed on disk. Run /reload-plugins to apply updates.(一次性提示) |
| C | 运行 /reload-plugins |
● Reloaded extensions: 1 extension · 2 commands · 1 skill · 1 agent · 0 hooks · 0 extension MCP servers · 0 extension LSP servers——步骤 A 中热加的文件被计入 |
2)测试 —— 作者套件 + 真实文件系统 E2E + 对抗式变异
(见上方第二张图)
- PR 自带测试 341 / 341 全绿(core 195 + cli 146,共 11 个文件)。
- 真实 chokidar E2E(为本次评审新增): 现有套件把
chokidar+node:fs都 mock 了、fire 合成事件,所以我写了一个 harness,用真 watcher 对真临时目录做真编辑。9/9,连续 4 次确定性通过——commands|skills|agents → content、hooks|qwen-extension.json|QWEN.md → stale、软链扩展源 →content、.DS_Store|.swp|README.md → 忽略。 - 变异测试——5/5 全部被捕获: 从
AUTO_REFRESH_DIRS删掉skills(单测和真实 E2E 同时变红)、isSuppressed()→false、汇总分隔符、throw hookReloadError、以及删掉 agent 作用域 hook 的保留——每一个都让对应套件变红,还原后干净转绿。 --bare→ 不启动 watcher 在源码中有门控(gemini.tsx:621,isBareMode(argv.bare) ? undefined : new ExtensionFileWatcher(...)),并有 bare-mode 测试覆盖。
备注(非阻塞,留档)
- 唯一被上抛而非吞掉的错误路径——hook 重载失败(
refreshExtensionRuntime重新 throwhookReloadError)——是真实且被测试的(删掉throw后变异变红)。其余静默路径(ENOSPC、MCP 启动、/hooks禁用状态跨重载丢失)是作者已明确声明的超范围项。 - 在 macOS 上,FSEvents 在快速多文件写入时偶发对 sibling 文件的连带 re-stat。这是操作系统层面的 watcher 特性(用裸
chokidar也能复现,非本 PR 特有),被awaitWriteFinish(200ms)+ExtensionRefreshState的"只提示一次"幂等吸收。最坏情况只是多一次/reload-plugins提示,绝不会误分类。 - 按设计,
SUPPRESS_AFTER_MS = 1000意味着在程序化 enable/disable 结束后约 1 秒内的用户文件编辑会被有意忽略(防自触发)。合理的权衡,仅作说明。
总结: 行为与描述一致,hook 路径的错误上抛有效,测试站得住。从验证角度 LGTM,可以合并。🚢
Verified locally on macOS with a from-source qwen bundle; screenshots are faithful renders of the real captured terminal output.
|
@qwen-code /triage |
|
Third triage pass on this PR. Since the last run (July 6), there's been a /review cycle, a maintainer's end-to-end tmux verification on Linux, and a merge conflict resolution. The code has matured significantly. Running through the gates again with the current state. Template looks good ✓ — all required sections filled in, bilingual description, risk disclosure, test-plan steps with OS matrix. Problem is real: extension developers currently have to type Direction is aligned — auto-detecting extension file changes and hot-reloading content while prompting for config/hooks is exactly how developers expect a plugin system to behave. No product-direction concerns. Size: core paths ( Approach: chokidar file watcher with a three-way classification (auto-refresh for commands/skills/agents, stale-prompt for config/hooks, ignore for everything else) plus a shared Moving to code review. 🔍 中文说明第三次 triage。自上次运行以来,经历了 /review 周期、维护者在 Linux 上的端到端 tmux 验证,以及合并冲突解决。代码已显著成熟。 模板完整 ✓。问题真实存在:扩展开发者目前每次编辑磁盘上的文件都需要手动输入 规模:核心路径 383 行生产代码(4 个文件),低于 500 行升级阈值。完整 PR 约 1,647 行生产代码(36 个文件,含约 270 行 i18n 翻译数据和约 800 行测试),触发非阻塞大 PR 建议。范围内聚——拆分会导致功能不完整。 方案:chokidar 文件监听器加三路分类(commands/skills/agents 自动刷新,config/hooks 提示重载,其他忽略)加上监听器与 UI 之间的共享 进入代码审查 🔍 — Qwen Code · qwen3.7-max |
Code ReviewIndependent proposal: I'd use chokidar to watch the user extension directory plus linked extension source directories. Classify each file change as either "content" (commands, skills, agents — safe to hot-reload silently) or "config" (manifest, hooks, context files — needs full The PR's implementation matches this closely and goes further in good ways:
The One issue found: in } finally {
if (tempDir) {
try {
await fs.promises.rm(tempDir, { recursive: true, force: true });
} catch {
// temp dir cleanup best-effort; endMutation must always run
}
}
endMutation();
}Unit Tests357 tests across 11 suites, all passing. Coverage includes happy paths, failure modes (MCP fatal, LSP partial failure, hook rollback, cache failure preservation), lifecycle boundaries (mutation events around enable/disable/install/uninstall/update), state preservation (reload-in-progress deferral, post-reload re-emission), and content-refresh serialization with the 5-pass limit. Test count grew from 341 → 357 across review iterations — the author added tests specifically for the edge cases reviewers flagged. Real-Scenario TestingRelying on maintainer verification (wenshao, July 8, on Linux with the real esbuild bundle in tmux). The maintainer drove all 9 test-plan steps with the actual CLI and reported: Mechanism proof + negative control:
No correctness issues found by the maintainer. Clean merge, load-bearing tests, behavior matches spec. 🐧 Linux status: I didn't duplicate this testing — the maintainer's verification is more authoritative than anything I could orchestrate in headless CI for this particular feature (it requires live filesystem mutations to extension directories with chokidar debounce timing). 中文说明代码审查独立方案: 使用 chokidar 监听用户扩展目录及链接扩展源目录。将每个文件变更分为"内容"类(commands、skills、agents——可安全静默热重载)或"配置"类(清单、钩子、上下文文件——需要完整的 PR 的实现与此高度一致,并在以下方面有好的改进:
发现一个问题: 单元测试11 个测试套件共 357 个测试全部通过。覆盖正常路径、失败模式(MCP 致命、LSP 部分失败、钩子回滚、缓存失败保留)、生命周期边界、状态保留和内容刷新序列化。 真实场景测试依赖维护者验证(wenshao,7月8日,Linux,真实 esbuild 产物,tmux)。维护者驱动了所有 9 个测试计划步骤并报告: — Qwen Code · qwen3.7-max |
|
Stepping back to look at the whole picture. This is a well-scoped feature that solves a real pain point. Extension developers iterating on skill files, commands, or agents shouldn't have to manually reload after every save — that's table stakes for a plugin system. The problem is documented in #3696 and the PR addresses it directly. The implementation is careful where it needs to be. The three-way file classification (auto / stale / ignore) is the right split — content files are safe to hot-reload, but hooks and config changes need a coordinated full rebuild because they can affect command routing, security-sensitive hook execution, and cache coherency. The My independent proposal matched the PR's architecture closely. I don't see a simpler path that would solve this problem. The scope feels right — the What gives me confidence: the maintainer's tmux verification is thorough — real TUI output, mechanism proof via debug logs, negative control with The one issue I flagged — At 383 production lines in core paths and ~1,647 total production lines, this is a substantial contribution from a fork. But the code is cohesive, well-tested (357 tests), and the maintainer has already verified it end-to-end on Linux and recommends merge. Approving. The 中文说明退一步看全局。 这是一个范围合理的功能,解决了真实的痛点。迭代技能文件、命令或代理的扩展开发者不应每次保存后都手动重载——这是插件系统的基本要求。问题在 #3696 中有记录,PR 直接解决了它。 实现在需要仔细的地方很仔细。三路文件分类(auto / stale / ignore)是正确的分割——内容文件可安全热重载,但钩子和配置变更需要协调的完整重建,因为它们可能影响命令路由、安全敏感的钩子执行和缓存一致性。 我的独立方案与 PR 架构高度一致。没有看到更简路径。范围合理—— 给予信心的因素:维护者的 tmux 验证全面——真实 TUI 输出、通过调试日志的机制证明、 标记的一个问题—— 核心路径 383 行、总计约 1,647 行生产代码是来自 fork 的实质性贡献。但代码内聚、测试充分(357 个测试),且维护者已在 Linux 上端到端验证并建议合并。 批准。 — Qwen Code · qwen3.7-max |
|
@qwen-code /triage |
0bcd48a to
d79c005
Compare
|
Please do not rebase or force-push to an active PR as it invalidates existing review comments. Note for future reference, the bots always squash all changes into a single commit automatically as part of the integration. 中文请勿对活跃的 PR 执行 rebase 或 force-push,因为这会使已有的评审评论失效。另外,供日后参考:作为集成流程的一部分,机器人始终会自动将所有改动压缩(squash)为单个提交。 |
|
@qwen-code /resolve |
Resolved import conflict in slashCommandProcessor.ts by combining the PR's extension reload imports (AppEvent, t, refreshExtensionContentRuntime, EXTENSION_RELOAD_FAILED_REASON, ExtensionRefreshState) with main's expanded commands.js import (parseStackedSlashCommands, MAX_STACKED_SKILLS). Both sets of imports are used in the file. Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
|
Qwen Code resolved the merge conflicts and pushed the branch update. Merge Conflict Resolution Summary — PR #6347Base branch
Merge performed
Conflicted file
ResolutionThe conflict was in the import block at the top of the file. Both sides extended the same
Resolution: Combined both sides. The Commit
Auto-merged files (no manual intervention needed)
|
|
@qwen-code /triage |
wenshao
left a comment
There was a problem hiding this comment.
No new issues found. LGTM! ✅
— qwen3.7-max via Qwen Code /review
qwen-code-ci-bot
left a comment
There was a problem hiding this comment.
Reviewed — no blockers. Suggestion-level recommendations are in the Suggestion summary comment below.
Suggestions — commit
|
| File | Issue | Suggested fix |
|---|---|---|
packages/core/src/extension/extensionManager.ts:1628 |
updateExtension finally block: fs.promises.rm(tempDir) can throw before endMutation(), leaving the watcher permanently suppressed |
Wrap fs.promises.rm in its own try/catch so endMutation() always runs |
Needs Human Review (low confidence):
packages/cli/src/config/extension-refresh-state.ts+packages/cli/src/ui/commands/reload-plugins-command.ts+packages/cli/src/ui/AppContainer.tsx— Three sites createnew ExtensionRefreshState()as a fallback. If any fires, the event bus disconnects silently. Consider adding aconsole.warnin each fallback.packages/cli/src/config/extension-refresh-state.ts:89—markExtensionsReloadFailedhas noreloadInProgressprecondition guard. All current callers are correct, but the API could be hardened.
— qwen3.7-max via Qwen Code /review
✅ Verification report — extension file-watch / hot-reloadI verified this PR end-to-end by merging it into current
1) Real TUI behavior (A, B, C)
2) Mechanism proof + negative control + unit suites
Notes for the maintainer
No correctness issues found. Clean merge, load-bearing tests, behavior matches the spec. 👍 中文版(点击展开)✅ 验证报告 —— 扩展文件监控 / 热重载我通过将本 PR 合并进当前
1)真实 TUI 行为(A / B / C)—— 见上方第一张图
2)机制证明 + 反向对照 + 单测 —— 见上方第二张图
给维护者的说明
未发现正确性问题。 干净合并、测试有效锁定、行为符合规范。👍 Verified on Linux by driving the real bundle (merge of |
|
@qwen-code /triage |
qwen-code-ci-bot
left a comment
There was a problem hiding this comment.
LGTM, looks ready to ship. ✅
One minor fix recommended before merge: wrap fs.promises.rm(tempDir) in updateExtension's finally block with its own try/catch so endMutation() always runs (prevents permanent watcher suppression if temp dir cleanup fails). The maintainer can decide whether to address this now or in a follow-up.
macOS tmux verification addendum — hooks / MCP / LSPI ran one extra hands-on pass for the runtime pieces that were not covered deeply in the earlier tmux report: extension hooks, extension MCP, and extension LSP.
Results
The MCP server log confirmed a real restart and JSON-RPC handshake/list flow:
The LSP server log confirmed
The following model call failed with Verdict: this extra tmux pass covers the reload path for hooks, extension MCP reconnect, and extension LSP initialization. No new correctness issue found from these runtime checks. |
yiliang114
left a comment
There was a problem hiding this comment.
Thanks for the careful follow-up here.
Approving from my side as well. I did an additional macOS tmux pass covering hooks, extension MCP, and extension LSP on the current head, and I don't see a correctness blocker for merge. The PR is also already mergeable, with the active required-looking checks green or skipped as expected for this run.
A few follow-ups are still worth tracking, but I don't think they need to block this PR:
updateExtensionshould eventually wrap temp-dir cleanup soendMutation()always runs even iffs.promises.rm(tempDir)throws.- The fallback
new ExtensionRefreshState()paths could use a warning/assertion, since a fallback state would silently disconnect the event bus. markExtensionsReloadFailedcould be hardened with areloadInProgressguard.- The CLI
/reload-pluginspath and daemonPOST /workspace/extensions/refreshpath now share the lower-level runtime refresh throughrefreshTools(), but their product semantics still differ. The daemon/ACP path currently swallowsrefreshTools()failures and returns{ ok: true }, while the CLI path surfaces reload failures. Worth aligning in a follow-up. - The config/hook-stale behavior and actual debounce latency are worth documenting, since they are intentional but not obvious.
These can be handled as polish/follow-up issues. The current implementation and test coverage look good enough to merge.










What this PR does
Adds a file watcher on extension directories so that editing extension files on disk is automatically detected. Content changes to commands, skills, and agent files are applied inline without user action. Configuration and hook changes prompt the user once to run
/reload-plugins.The runtime refresh logic that was previously inline in
ExtensionManager(restart MCP servers, reload skill/subagent caches, refresh hierarchical memory) is extracted into a singlerefreshExtensionRuntimefunction used by all enable/disable/install/uninstall paths as well as the new/reload-pluginscommand.The slash command reports a summary of what was loaded: extension count, commands, skills, agents, hooks, MCP servers, and LSP servers, in the user's locale.
Hook configuration is now reloaded on extension changes. Agent-scoped hooks are preserved across the reload, and a failure during hook rebuild restores the previous state.
Extension manager mutations (enable, disable, install, uninstall, update, scope changes, favorites, MCP server toggles) are now wrapped with a lifecycle listener so the file watcher can suppress itself during programmatic changes and restart watching after the mutation settles.
Why it's needed
Today there is no way to detect extension file changes on disk. Every edit to a command, skill, hook, or extension config requires the user to manually run
/reload-plugins. During extension development, where you iterate on files rapidly, the manual step adds significant friction.Extension runtime refresh was split across two private methods on
ExtensionManager(refreshMemory/refreshTools) with slightly different call chains depending on the caller, and hooks were never reloaded mid-session. This consolidates the refresh into one function used by every path.Reviewer Test Plan
How to verify
commands/,skills/, oragents/directory and save.qwen-extension.json, a hook file, or a context file./reload-plugins— a summary should appear showing counts like "1 extension · 2 commands · 3 skills · 4 agents · 5 hooks · 1 extension MCP server"./extensions link), edit a file in the linked directory, and confirm the watcher detects the change.--bare— no watcher should be started.Evidence (Before & After)
Before: Editing a skill file in an extension has no effect. The user must type
/reload-pluginsmanually.After: The skill is auto-refreshed within ~250ms of saving. Config and hook changes prompt the user once with a specific message.
Tested on
Environment (optional)
npm run devon macOS. Unit tests and i18n strict-parity tests pass.Risk & Scope
/reload-pluginsare not surfaced to the user (only logged). Hook disable state set via/hooksis lost across extension reloads. No backend daemon — the watcher stops with the process.ExtensionManager.refreshMemory()was removed. It had no external callers — it was only called internally byrefreshTools().Linked Issues
Refs #3696
中文说明
这个 PR 做了什么
为扩展目录增加了文件监控,编辑磁盘上的扩展文件可被自动检测。对 commands、skills、agent 文件的内容变更会内联自动应用,无需用户操作。配置和钩子变更会一次性提示用户运行
/reload-plugins。之前分散在
ExtensionManager中的运行时刷新逻辑(重启 MCP 服务器、重新加载 skill/subagent 缓存、刷新层次化记忆)被提取为一个refreshExtensionRuntime函数,所有 enable/disable/install/uninstall 路径以及新的/reload-plugins命令都使用它。斜杠命令会以用户的语言报告加载内容汇总:扩展数量、命令、技能、代理、钩子、MCP 服务器和 LSP 服务器。
钩子配置现在会在扩展变更时重新加载。代理作用域的钩子会在重载过程中保留,钩子重建失败时会恢复到之前的状态。
扩展管理器变更操作(启用、禁用、安装、卸载、更新、作用域变更、收藏、MCP 服务器开关)现在通过生命周期监听器包裹,使文件监控器能够在程序化变更期间抑制自身,并在变更结束后重新开始监控。
为什么需要
当前无法检测磁盘上的扩展文件变更。每次编辑命令、技能、钩子或扩展配置文件,都需要用户手动运行
/reload-plugins。在扩展开发中频繁迭代文件时,手动操作增加了显著的摩擦。扩展运行时刷新分散在
ExtensionManager的两个私有方法中(refreshMemory/refreshTools),调用链因调用方不同而略有差异,且钩子从未在会话中间被重新加载。此次将其整合为一个所有路径都使用的函数。Reviewer 测试计划
如何验证
commands/、skills/或agents/目录下的文件并保存。qwen-extension.json、钩子文件或上下文文件。/reload-plugins——应显示类似 "1 个扩展 · 2 个命令 · 3 个技能 · 4 个代理 · 5 个钩子 · 1 个扩展 MCP 服务器" 的汇总。--bare运行——不应启动 watcher。Before / After
Before:编辑扩展中的技能文件无任何效果。用户必须手动输入
/reload-plugins。After:技能在保存后约 250ms 内自动刷新。配置和钩子变更会一次性提示用户,并给出具体消息。
测试平台
环境(可选)
npm run dev在 macOS 上。单元测试和 i18n 严格校验测试均通过。风险与范围
/reload-plugins期间 MCP 服务器启动失败不会提示用户(仅记录日志)。通过/hooks设置的钩子禁用状态在扩展重载后会丢失。没有后台守护进程——watcher 随进程退出而停止。ExtensionManager.refreshMemory()已移除。该方法无外部调用方——仅由refreshTools()内部调用。关联 Issue
Refs #3696